package com.ts.api.module.product.service.impl;

import com.gitee.apanlh.util.base.BigDecimalUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.constant.productbill.ProductBillEnum;
import com.ts.api.common.transaction.TransactionSupport;
import com.ts.api.module.product.dao.ProductBillDao;
import com.ts.api.module.product.dao.ProductDao;
import com.ts.api.module.product.dao.ProductPlanDao;
import com.ts.api.module.product.entity.bo.ProductAmountBO;
import com.ts.api.module.product.entity.po.ProductBillPO;
import com.ts.api.module.product.entity.po.ProductPO;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import com.ts.api.module.product.service.ProductAmountService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

@Service
public class ProductAmountServiceImpl implements ProductAmountService {

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private TransactionSupport transactionSupport;
    @Autowired
    private ProductPlanDao productPlanDao;
    @Autowired
    private ProductDao productDao;
    @Autowired
    private ProductBillDao productBillDao;

    @Override
    public boolean isDeduct(BigDecimal balance, BigDecimal price) {
        //  单价0自动放行
        if (this.hasZeroPrice(price)) {
            return true;
        }
        return BigDecimalUtils.compare(balance, price) >= 0;
    }

    /**
     *  是否计划单价为0
     *
     *  @return  hasZeroPrice
     */
    private boolean hasZeroPrice(BigDecimal price) {
        return Eq.strOr(price.toString(), "0", "0.00");
    }

    @Override
    public BigDecimal deduct(ProductAmountBO productAmountBO) {
        RLock lock = redissonClient.getLock("bill_lock:" + productAmountBO.getProductId().toString());
        lock.lock(10, TimeUnit.SECONDS);
        try {
            return transactionSupport.requiresNew(() -> {
                //  扣款余额-修改后直接扣除
                ProductPlanPO productPlanPO = productPlanDao.get(productAmountBO.getProductPlanId());

                // 获得【扣款类型】
                ProductBillEnum deductType = productAmountBO.obtainDeductType();
                // 获得【价格】
                BigDecimal price = productAmountBO.obtainPrice(productPlanPO.getShare(), productPlanPO.getPrice());
                // 【余额】
                BigDecimal balance = productPlanPO.getProductBalance();
                // 计算【剩余余额】
                BigDecimal remainingBalance = BigDecimalUtils.minus(balance, price);

                //  记录账单
                ProductBillPO productBillPO = new ProductBillPO();
                productBillPO.setLoanProductId(productAmountBO.getProductId());
                productBillPO.setLoanProductPlanId(productAmountBO.getProductPlanId());
                productBillPO.setLoanUserId(productAmountBO.getUserId());
                productBillPO.setPhoneMd5(productAmountBO.getPhoneMd5());
                productBillPO.setLoanChannelId(productAmountBO.getLoanChannelId());
                productBillPO.setApiClientId(productAmountBO.getApiClientId());
                productBillPO.setAmount(price);
                productBillPO.setAccountBalance(remainingBalance);
                productBillPO.setCurrentBalance(balance);
                productBillPO.setType(deductType.getType());
                if (ValidParam.isEmpty(productAmountBO.getCreateTime())) {
                    productBillPO.setCreateTime(DateUtils.currentTime());
                } else {
                    productBillPO.setCreateTime(productAmountBO.getCreateTime());
                }
                //  用于修复更新时间
                if (ValidParam.isNotEmpty(productAmountBO.getUpdateTime())) {
                    productBillPO.setUpdateTime(productAmountBO.getUpdateTime());
                }

                productBillDao.insert(productBillPO);

                //  修改余额
                ProductPO productPO = new ProductPO();
                productPO.setId(productAmountBO.getProductId());
                productPO.setBalance(remainingBalance);
                productDao.updateBalance(productPO);

                return price;
            });
        } finally {
            lock.unlock();
        }
    }

}
